package com.leinao.category.service.impl;

import com.leinao.category.dao.CategoryMapper;
import com.leinao.category.dto.CategoryCount;
import com.leinao.category.dto.CategoryDto;
import com.leinao.category.dto.CategoryRelationDto;
import com.leinao.category.model.BatchCategoryRelation;
import com.leinao.category.model.Category;
import com.leinao.category.model.CategoryRelation;
import com.leinao.category.service.CategoryService;
import com.leinao.commons.Response;
import com.leinao.constant.CategoryCustomTypeEnum;
import com.leinao.constant.CategoryTypeEnum;
import com.leinao.constant.Constant;
import com.leinao.constant.ProjectErrorEnum;
import com.leinao.login.dto.LoginResultDto;
import com.leinao.project.dao.PaiDataSetMapper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @Description 算法、数据集分类服务
 * @author lizi
 * @date 2019/03/06 下午5:15
 * @Version 1.0
 */
@Service
public class CategoryServiceImpl implements CategoryService {
	
	private static Logger logger = LoggerFactory.getLogger(CategoryServiceImpl.class);

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
	private PaiDataSetMapper paiDataSetMapper;

	/***
	 * @Description 获取分类列表信息
	 *
	 * @param type : 类型: 1-算法，2-数据集
	 * @author lizi
	 * @date 2019/03/06 下午5:15
	 */
	@Override
	public Response<List<CategoryDto>> getCategoryListByType(Integer type) {
		List<CategoryDto> categoryList = categoryMapper.getCategoryList(type);

		return Response.ok(categoryList == null ? Collections.emptyList() : categoryList);
	}

	/***
	 * @Description 获取分类树信息
	 *
	 * @param type : 类型: 1-算法，2-数据集
	 * @author lizi
	 * @date 2019/03/11 下午5:15
	 */
	@Override
	public Response<List<CategoryDto>> getCategoryTreeByType(Integer type) {
		List<CategoryDto> categoryList = categoryMapper.getCategoryList(type);
		if(CollectionUtils.isEmpty(categoryList)) {
			return Response.ok(Collections.emptyList());
		}

		// 分类按照ParentId转换成Map，以便程序匹配父子关系
		Map<Long, List<CategoryDto>> childCategoryMap = categoryList.stream().collect(Collectors.toMap(CategoryDto::getParentId,
							category ->  {
								List<CategoryDto> childCategoryList = new ArrayList<>();
								childCategoryList.add(category);
								return childCategoryList;
							},
							(List<CategoryDto> value1, List<CategoryDto> value2) -> {
								value1.addAll(value2);
								return value1;
							}));

		// 一级分类
		List<CategoryDto> oneLevelCategoryList = childCategoryMap.get(Constant.CATEGORY_TREE_TOP_ID);
		if(CollectionUtils.isEmpty(oneLevelCategoryList)) {
			return Response.ok(Collections.emptyList());
		}

		// 初始化子分类
		oneLevelCategoryList.forEach(oneLevelCategory -> {
			initCategoryTree(oneLevelCategory, childCategoryMap);
		});

		return Response.ok(oneLevelCategoryList);
	}

	/***
	 * @Description 获取主体分类关联关系
	 *
	 * @param objectId : 主体ID
	 * @param type : 类型: 1-算法，2-数据集
	 * @author lizi
	 * @date 2019/03/06 下午5:15
	 */
	@Override
	public Response<List<CategoryRelationDto>> getCategoryRelationList(Long objectId, Integer type) {
		List<CategoryRelationDto> categoryRelationList = categoryMapper.getCategoryListByObjectIdAndType(objectId, type);

		return Response.ok(categoryRelationList == null ? Collections.emptyList() : categoryRelationList);
	}

	/***
	 * @Description 删除分类
	 *
	 * @param categoryRelationId : 分类关联ID
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2019/03/06 下午5:15
	 */
	@Override
	@Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
	public Response<Void> deleteCategoryRelation(Long categoryRelationId, LoginResultDto userInfo) {
	    // 获取分类关联信息
        CategoryRelation categoryRelation = categoryMapper.getCategoryRelation(categoryRelationId);

        // 验证分类是否存在和是否是属于该用户的
        if(categoryRelation == null || !userInfo.getUserId().equals(categoryRelation.getUserId())) {
            return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.CATEGORY_RELATION_NOT_EXISTS.getSeq(), ProjectErrorEnum.CATEGORY_RELATION_NOT_EXISTS.getDesc(), null);
        }

		// 插入分类信息
		long now = System.currentTimeMillis();
		categoryMapper.deleteCategoryRelation(categoryRelationId, now);

		return Response.ok();
	}

	/***
	 * @Description 批量保存分类信息
	 *
	 * @param batchCategoryRelation : 分类批量信息
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2019/03/08 下午5:15
	 */
	@Override
	@Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
	public Response<Void> saveCategoryRelationList(BatchCategoryRelation batchCategoryRelation, LoginResultDto userInfo) {
		Long objId = batchCategoryRelation.getObjId();
		Integer type = batchCategoryRelation.getType();
		List<CategoryRelation> categoryRelationList = batchCategoryRelation.getCategoryRelationList();
		if((objId == null || objId == 0) || (type == null || type == 0)) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.CATEGORY_PARAM_EMPTY.getSeq(), ProjectErrorEnum.CATEGORY_PARAM_EMPTY.getDesc(), null);
		}

		// 获取存在的分类关联信息
		List<CategoryRelationDto> dbCategoryRelationList  = categoryMapper.getCategoryListByObjectIdAndType(objId, type);

		// 项目数据集关系列表
		List<Long> dbCategoryRelationIdList = dbCategoryRelationList.stream().map(CategoryRelationDto::getId).collect(Collectors.toList());
		dbCategoryRelationIdList = dbCategoryRelationIdList == null ? new ArrayList<>() : dbCategoryRelationIdList;

		// 需要新增的项目数据集关系列表
		List<CategoryRelation> insertCategoryRelationList = new ArrayList<>();

		// 所有需要保留的项目数据集关系列表
		long now = System.currentTimeMillis();
		Set<Long> categoryRelationSet = new LinkedHashSet<>();
		if(!CollectionUtils.isEmpty(categoryRelationList)) {
			categoryRelationList.forEach(categoryRelation -> {
				if(categoryRelation.getId() != null && categoryRelation.getId() != 0) {
					categoryRelationSet.add(categoryRelation.getId());
					return;
				}

				// categoryId和name必须传入一个
				Long categoryId = categoryRelation.getCategoryId();
				if((categoryId == null || categoryId == 0) && StringUtils.isEmpty(categoryRelation.getName())) {
					return;
				}
				categoryRelation.setObjId(objId);
				categoryRelation.setType(type);
				categoryRelation.setUserId(userInfo.getUserId());
				categoryRelation.setCreateTime(now);
				categoryRelation.setUpdateTime(now);
				insertCategoryRelationList.add(categoryRelation);
			});
		}

		// 需要删除的项目数据集关系列表
		List<Long> deleteCategoryRelationList = new ArrayList<>(dbCategoryRelationIdList);
		deleteCategoryRelationList.removeAll(categoryRelationSet);
		if(!CollectionUtils.isEmpty(deleteCategoryRelationList)) {
			categoryMapper.deleteCategoryRelationList(deleteCategoryRelationList, now);
		}

		// 批量添加分类关联信息，由于每次做多添加三个标签，所以此处使用循环插入
		insertCategoryRelationList.forEach(categoryRelation -> {
			// 自定义标签需要先往分类标签表插入数据，再关联返回的分类ID
			initCustomCategory(categoryRelation, now);

			// 保存关联关系
			categoryMapper.insertCategoryRelation(categoryRelation);
		});

		return Response.ok();
	}

	/***
	 * @Description 添加分类
	 *
	 * @param categoryRelation : 分类信息
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2019/03/06 下午5:15
	 */
	@Override
	@Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
	public Response<Long> addCategoryRelation(CategoryRelation categoryRelation, LoginResultDto userInfo) {
		// 获取需要添加的分类信息
		Long categoryId = categoryRelation.getCategoryId();
		String categoryName = categoryRelation.getName();
		if((categoryId == null || categoryId == 0) && StringUtils.isEmpty(categoryName)) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.CATEGORY_ID_NAME_REQUIRED.getSeq(), ProjectErrorEnum.CATEGORY_ID_NAME_REQUIRED.getDesc(), null);
		}

		// 插入分类信息
		long now = System.currentTimeMillis();
		categoryRelation.setUserId(userInfo.getUserId());
		categoryRelation.setCreateTime(now);
		categoryRelation.setUpdateTime(now);

		// 系统分类，名称只为空
		initCustomCategory(categoryRelation, now);

		// 插入分类关联关系
		categoryMapper.insertCategoryRelation(categoryRelation);

		return Response.ok(categoryRelation.getId());
	}

	/***
	 * @Description 递归初始化子分类
	 *
	 * @param category : 分类
	 * @param childCategoryMap : 子节点集合
	 * @author lizi
	 * @date 2019/03/11 下午5:15
	 */
	private void initCategoryTree(CategoryDto category, Map<Long, List<CategoryDto>> childCategoryMap) {
		// 防止数据问题造成死循环，查询到的数据就进行移除
		List<CategoryDto> childCategoryList = childCategoryMap.remove(category.getId());
		if(CollectionUtils.isNotEmpty(childCategoryList)) {
			category.setChildList(childCategoryList);
			for(CategoryDto childCategory : childCategoryList) {
				initCategoryTree(childCategory, childCategoryMap);
			}
		} else {
			// 没有子分类的讲子节点设置为空数组，防止前端undefined
			category.setChildList(Collections.emptyList());
		}
	}

	/***
	 * @Description 初始化你自定义标签
	 *
	 * @param categoryRelation : 分类关联信息
	 * @param now : 当前时间
	 * @author lizi
	 * @date 2019/03/14 下午5:15
	 */
	private void initCustomCategory(CategoryRelation categoryRelation, long now) {
		if(categoryRelation.getCategoryId() != null && categoryRelation.getCategoryId() != 0) {
			return;
		}
		CategoryDto categoryDto = categoryMapper.getCustomCategoryByName(categoryRelation.getName());
		if(categoryDto == null) {
			Category category = new Category();
			category.setName(categoryRelation.getName());
			category.setType(CategoryTypeEnum.CUSTOM.getType());
			category.setCustomType(CategoryCustomTypeEnum.CUSTOM.getType());
			category.setCreateTime(now);
			category.setUpdateTime(now);
			categoryMapper.insertCategory(category);
			categoryRelation.setCategoryId(category.getId());
		} else {
			categoryRelation.setCategoryId(categoryDto.getId());
		}
	}

	/**
	  * @Description 获取公开项目关联最多的5个标签
	  * @param type 1:公开项目  2:数据集
	  * @return	公开项目关联最多的5个标签
	  * @author:    weiwei
	  * @Date:  2019/3/14 11:30
	  */
	@Override
	public Response<List<CategoryDto>> getTopFiveRelationCategory(Integer type) {

		List<CategoryDto> categoryList = categoryMapper.getTopFiveRelationCategory(type);

		return Response.ok(categoryList == null ? Collections.emptyList() : categoryList);
	}

	/**
	  * @Description 获取公开项目和公开数据集关联的标签个数
	  * @return com.leinao.commons.Response<com.leinao.category.dto.CategoryCount> 公开项目和公开数据集标签个数
	  * @author:    weiwei
	  * @Date:  2019/4/2 14:12
	  */
	@Override
	public Response<CategoryCount> getCategoryCount() {
		CategoryCount categoryCount = new CategoryCount();
		categoryCount.setProjectCount(categoryMapper.getCategoryCountByType(1));
		categoryCount.setDateBaseCount(categoryMapper.getCategoryCountByType(2));
		return Response.ok(categoryCount);
	}
}